#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "duiPlus.h"
#include "common.h"
#include "cJSON.h"
#include <assert.h>
#ifdef __WIN32
#include "windows.h"
#endif

#define BUFLEN 255

static int vadBegin = 0;
static int vadEnd = 0;
static int vadPcm = 0;
static int sspeWkp = 0;
static int sspeAecPcm = 0;

struct duiPlus_t *duiPlus;
int vadIndex;

//int g_wakeup_status = 0;
typedef void (*pduiPlusLiteSspeCallback)(int);
pduiPlusLiteSspeCallback duiPlusSspeCallback_;

static char *TAG = "AI-daemo";

static void _deletePlaceFun(char *str){
	int i=0;
	char *p=str;
	while(*p){
		if(*p!=' ')
			str[i++]=*p;
		p++;
	}
	/*除了for循环遍历，也可while循环遍历。注意 p++在if语句后，不然会漏掉第一个字符。*/
	str[i]='\0';
	/*循环完毕要主动添加'\0'结束字符串。*/
}

static char* _duiPlusLiteSspeHandle(void *userdata, int index, char * data, int len, int type, int event){
	switch(event)
	{
		case DUIPLUS_EVENT_MSG_LITE_SSPE_WAKEUP:
		{
			if(type == DUIPLUS_DATA_TYPE_JSON){
				printf("wqy xxxxxxxxxxxxxxxxxxxx wakeup info : %s\n", data);
				//g_wakeup_status = 1;
				duiPlusSspeCallback_(1);
				if (vadIndex >= 0)
				{
					char *params = "{\"pauseTime\":300}";
					duiPlusStartVad(duiPlus, vadIndex, params);

				}
				sspeWkp = 1;
			}
			break;
		}
		case DUIPLUS_EVENT_MSG_LITE_SSPE_AEC:
		{
			if(type == DUIPLUS_DATA_TYPE_BINARY){
				printf("xxxxxxxxxxxxxxxxxxxx aec pcm len: %d\n", len);

				duiPlusFeedVad(duiPlus, vadIndex, data, len, NULL);

				

				sspeAecPcm += len;
			}
			break;
		}
		case DUIPLUS_EVENT_MSG_ERROR:
		{
			if(type == DUIPLUS_DATA_TYPE_JSON)
			{
				printf("*************************error: %s\n", data);
			}
		}
	}
	//printf("*****************************origin: %d\n", len);
	return NULL;
}


static char* _duiPlusLiteVadHandle(void *userdata, int index, char * data, int len, int type, int event){
	switch(event)
	{
		case DUIPLUS_EVENT_MSG_LITE_VAD:
		{
			if(type == DUIPLUS_DATA_TYPE_BINARY){
				printf("xxxxxxxxxx vad pcm len: %d\n", len);
				vadPcm++;
			}
			if(type == DUIPLUS_DATA_TYPE_JSON){
				printf("xxxxxxxxxx vad status: %s\n", data);
				cJSON * root_js = data ? cJSON_Parse(data) : NULL;
				cJSON * status_js = root_js ? cJSON_GetObjectItem(root_js, "status") : NULL;
				if(status_js && status_js->type == cJSON_Number){
					if(status_js->valueint == 1) vadBegin = 1;
					if(status_js->valueint == 2) vadEnd = 1;
				}
				if(root_js) cJSON_Delete(root_js);
			}
			break;
		}
		case DUIPLUS_EVENT_MSG_ERROR:
		{
			if(type == DUIPLUS_DATA_TYPE_JSON)
			{
				printf("*************************error: %s\n", data);
			}
		}
	}
	//printf("*****************************origin: %d\n", len);
	return NULL;
}

void _externalRecorderFeedAudio(struct duiPlus_t *duiPlus, int index, char *audioPath, int channel, int type) {
	FILE * fp = fopen(audioPath, "rb");

	if(!fp) 
	{
		printf("fopen file failed\n");
		return ;
	}
	if (!strcmp(".wav", strrchr(audioPath, '.'))) {
		printf("wav seek 44 byte\n");
		fseek(fp, 44, SEEK_SET);
	}

	// int frameSize = 3200 * channel;
	int frameSize = 2450 * channel;
	if (frameSize <= 0 || frameSize % 2 != 0) {
		printf("frameSize is err: %d\n", frameSize);
		return ;
	}
	char* buf = malloc(frameSize);
	if (!buf) {
		printf("malloc buf err\n");
		return ;
	}

	while(1)
	{
		int ret = fread(buf, 1, frameSize, fp);
		printf("feed len: %d\n", ret);
		if (ret <= 0) break;
		if (type == 1) {
			duiPlusFeedVad(duiPlus, index, buf, ret, NULL);
		} else if (type == 2) {
            duiPlusFeedSspe(duiPlus, index, buf, ret, NULL);
        }
		usleep(100000);
	}
	free(buf);
	fclose(fp);
}

static void _test_vad(struct duiPlus_t * duiPlus){
	vadBegin = 0;
	vadEnd = 0;
	vadPcm = 0;
	char *vadCfg =
		"{\
		\"resBinPath\":\"./res/vad_aicar_v0.15.bin\",\
		\"cacheInCorePcm\":\"false\",\
		\"cacheRecvPcm\":\"false\"\
	}";

	vadIndex = duiPlusCreateVadIndex(duiPlus, vadCfg, _duiPlusLiteVadHandle, NULL);

}

static void run_duiplus(struct duiPlus_t *duiPlus, app_config_t config)
{
	vadBegin = 0;
	vadEnd = 0;
	vadPcm = 0;
	char vadCfg[1024] = {0};
	char *vadCfg_format = 
		"{\
		\"resBinPath\":\"%s\",\
		\"cacheInCorePcm\":\"false\",\
		\"cacheRecvPcm\":\"false\"\
	}";
	snprintf(vadCfg, sizeof(vadCfg) - 1, vadCfg_format, config.asr.vad_res);

	printf("vadCfg: %s\n", vadCfg);
	vadIndex = duiPlusCreateVadIndex(duiPlus, vadCfg, _duiPlusLiteVadHandle, NULL);

	char sspeCfg[1024] = {0};
	char *sspeCfg_format =
		"{\
            \"sspeBinPath\":\"%s\",\
            \"wakeupBinPath\":\"%s\",\
            \"rollBack\": 0,\
            \"env\": \"%s\",\
            \"cacheBFPcm\":\"false\",\
            \"cacheInCorePcm\":\"false\",\
            \"cacheRecvPcm\":\"false\",\
            \"cacheAecPcm\":\"false\",\
            \"cacheOutputPcm\":\"false\",\
            \"callbackSwitch\":{\
                \"wakeupCallback\":\"true\",\
                \"aecCallback\":\"true\"\
            }\
            }";

	snprintf(sspeCfg, sizeof(sspeCfg) - 1, sspeCfg_format,config.wakeup.sspeRes,config.wakeup.wakeupRes,config.wakeup.env);

	printf("sspeCfg: %s\n", sspeCfg);

	int engineIndex1 = duiPlusCreateSspeIndex(duiPlus, sspeCfg, _duiPlusLiteSspeHandle, NULL);

	if(engineIndex1>=0){
		duiPlusStartSspe(duiPlus, engineIndex1, NULL);

		_externalRecorderFeedAudio(duiPlus, engineIndex1, "./res/cap_out-1.wav", 2, 2);

		duiPlusStopVad(duiPlus, vadIndex, NULL);
		int count = 0;
		while(1){
			if(vadBegin == 1 && vadEnd == 1 && vadPcm > 0) break;
			sleep(1);
			count++;
			if(count == 10) break;
		}
		duiPlusReleaseVadIndex(duiPlus, vadIndex, NULL);
	}
}

// int main(int argc, char **argv)
int duiplus_main()
{
	app_config_t config = init("./res/app_config.json");

	// if (argc > 1)
	// {
	// 	strcpy(config.offline_audio_path, argv[1]);
	// }

	if (auth(config))
	{
		goto end;
	}

	// char *authcfg =
	// 	"{\
	// 	\"level\":3,\
	// 	\"productId\":\"279623158\",\
	// 	\"productKey\":\"13e1450a689b946515c89dc972bfc78d\",\
	// 	\"productSecret\":\"31a458978e91c8730d21db659dc1badd\",\
	// 	\"savedProfile\":\"./000c296663d8.txt\",\
    // 	\"productVersion\":\"0.1.2\",\
    // 	\"devInfo\":{\
    //     	\"deviceName\":\"000c296663d8\",\
    //     	\"platform\":\"linux\"\
    // 	}\
    // }";


    // int ret = duiPlusDoAuth(authcfg);
    // if(ret)
	// {
	// 	printf("auth failed\n");
	// 	duiPlusReleaseAuth();
	// 	return -1;
	// }

	char cfg[1024] = {0};
	char * cfg_fromat = 
	"{\
    	\"deviceId\":\"%s\",\
    	\"aliasKey\":\"test\",\
    	\"homePath\":\".\"\
	}";

	snprintf(cfg, sizeof(cfg) - 1, cfg_fromat,config.device_id);

	duiPlus = duiPlusNew(cfg, NULL, NULL);

	run_duiplus(duiPlus, config);

	duiPlusDelete(duiPlus);
	duiPlusReleaseAuth();

	printf("\n\n\ntest module: %s, vadBegin: %d, vadEnd:%d, vadPcm: %d, sspeWkp: %d, sspeAecPcm: %d\n\n\n\n", __FILE__, vadBegin, vadEnd, vadPcm, sspeWkp, sspeAecPcm);
	// assert(vadBegin==1);
	// assert(vadEnd==1);
	// assert(vadPcm>1);

end:
	deinit();

	return 0;
}


// add new interface wqy
int duiplus_index = 0;
int duiplus_init() {
	app_config_t config = init("./res/app_config.json");

	if (auth(config))
	{
		return -1;
	}

	char cfg[1024] = {0};
	char * cfg_fromat = 
	"{\
    	\"deviceId\":\"%s\",\
    	\"aliasKey\":\"test\",\
    	\"homePath\":\".\"\
	}";

	snprintf(cfg, sizeof(cfg) - 1, cfg_fromat,config.device_id);
	duiPlus = duiPlusNew(cfg, NULL, NULL);


	//............
	char vadCfg[1024] = {0};
	char *vadCfg_format = 
		"{\
		\"resBinPath\":\"%s\",\
		\"cacheInCorePcm\":\"false\",\
		\"cacheRecvPcm\":\"false\"\
	}";
	snprintf(vadCfg, sizeof(vadCfg) - 1, vadCfg_format, config.asr.vad_res);

	printf("vadCfg: %s\n", vadCfg);
	vadIndex = duiPlusCreateVadIndex(duiPlus, vadCfg, _duiPlusLiteVadHandle, NULL);
	printf("vadIndex = %d\n", vadIndex);

	char sspeCfg[1024] = {0};
	char *sspeCfg_format =
		"{\
            \"sspeBinPath\":\"%s\",\
            \"wakeupBinPath\":\"%s\",\
            \"rollBack\": 0,\
            \"env\": \"%s\",\
            \"cacheBFPcm\":\"false\",\
            \"cacheInCorePcm\":\"false\",\
            \"cacheRecvPcm\":\"false\",\
            \"cacheAecPcm\":\"false\",\
            \"cacheOutputPcm\":\"false\",\
            \"callbackSwitch\":{\
                \"wakeupCallback\":\"true\",\
                \"aecCallback\":\"true\"\
            }\
            }";

	snprintf(sspeCfg, sizeof(sspeCfg) - 1, sspeCfg_format,config.wakeup.sspeRes,config.wakeup.wakeupRes,config.wakeup.env);

	printf("sspeCfg: %s\n", sspeCfg);

	// int engineIndex1 = duiPlusCreateSspeIndex(duiPlus, sspeCfg, _duiPlusLiteSspeHandle, NULL);
	// if(engineIndex1>=0){
	// 	duiPlusStartSspe(duiPlus, engineIndex1, NULL);
	// }

	int duiplus_index = duiPlusCreateSspeIndex(duiPlus, sspeCfg, _duiPlusLiteSspeHandle, NULL);
	if(duiplus_index>=0){
		duiPlusStartSspe(duiPlus, duiplus_index, NULL);
	}
}



void registerDuiPlusLiteSspeCallback(pduiPlusLiteSspeCallback callback) {
	duiPlusSspeCallback_ = callback;
}

int duiplus_deinit() {
	deinit();
}

int duiplusFeedBuff(char *buff, int len) {
	duiPlusFeedSspe(duiPlus, duiplus_index, buff, len, NULL);
	//usleep(100000);
}
